import re

from django_redis import get_redis_connection
from rest_framework import serializers

from goods.models import SKU
from users import constants
from users.models import User, Address


class UserSerializer(serializers.ModelSerializer):
    """用户序列化器类"""
    password2 = serializers.CharField(label='重复密码', write_only=True)  # 默认的write_only是Fault
    sms_code = serializers.CharField(label='短信验证码', write_only=True)
    allow = serializers.CharField(label='是否同意协议', write_only=True)
    token = serializers.CharField(label='JWT token', read_only=True)

    class Meta:
        model = User
        fields = ('id', 'username', 'password', 'mobile', 'password2', 'sms_code', 'allow', 'token')
        # 添加额外限制条件
        extra_kwargs = {
            'username': {
                'min_length': 5,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许5-20个字符的用户名',
                    'max_length': '仅允许5-20个字符的用户名',
                }
            },
            'password': {
                'write_only': True,
                'min_length': 8,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许8-20个字符的密码',
                    'max_length': '仅允许8-20个字符的密码',
                }
            }
        }

    def validate_mobile(self, value):
        # 手机号格式
        if not re.match(r'^1[3-9]\d{9}$', value):
            raise serializers.ValidationError('手机号格式不正确')

        # 验证手机号是否注册过
        count = User.objects.filter(mobile=value).count()
        if count > 0:
            raise serializers.ValidationError('手机号已存在')
        return value

    def validate_allow(self, value):
        # 是否同意协议
        if value != 'true':
            raise serializers.ValidationError('请同意协议')
        return value

    def validate(self, attrs):
        """attrs： 字典，客户端传递的所有数据"""

        # 查看两次密码是否一致
        password = attrs['password']
        password2 = attrs['password2']

        if password != password2:
            raise serializers.ValidationError('两次输入的密码不一致')

        # 短信验证码验证
        mobile = attrs['mobile']

        # 获取redis链接
        redis_conn = get_redis_connection('verify_codes')
        real_sms_code = redis_conn.get('sms_%s' % mobile)  # 这里得到是bytes类型
        if real_sms_code is None:
            raise serializers.ValidationError('验证码已过期')
        sms_code = attrs['sms_code']  # 字符串类型
        # if sms_code != real_sms_code.decode():
        if real_sms_code.decode() != sms_code:
            raise serializers.ValidationError('短信验证码错误')

        return attrs

    # 创建新用户　默认的 Serializer.Model 中的密码字段不加密明文，所以我们要重写创建用户函数
    def create(self, validated_data):
        """validated_data　字典　校验之后的数据"""

        # 移除无用的数据
        del validated_data['password2']
        del validated_data['sms_code']
        del validated_data['allow']

        user = User.objects.create_user(**validated_data)
        # 服务器生成一个jwt token的字符串：保留用户的身份信息
        from rest_framework_jwt.settings import api_settings

        # 生成payload的方法  载荷
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        # 给user增加token属性，保存jwt token的信息
        user.token = token

        return user


# import re
#
# from django_redis import get_redis_connection
# from rest_framework import serializers
#
# from users.models import User
#
#
# class UserSerializer(serializers.ModelSerializer):
#     """用户序列化器类"""
#     password2 = serializers.CharField(label='重复密码', write_only=True)
#     sms_code = serializers.CharField(label='短信验证码', write_only=True)
#     allow = serializers.CharField(label='是否同意协议', write_only=True)
#     token = serializers.CharField(label='JWT token', read_only=True)
#
#     class Meta:
#         model = User
#         fields = ('id', 'username', 'password', 'mobile', 'password2', 'sms_code', 'allow', 'token')
#
#         extra_kwargs = {
#             'username': {
#                 'min_length': 5,
#                 'max_length': 20,
#                 'error_messages': {
#                     'min_length': '仅允许5-20个字符的用户名',
#                     'max_length': '仅允许5-20个字符的用户名',
#                 }
#             },
#             'password': {
#                 'write_only': True,
#                 'min_length': 8,
#                 'max_length': 20,
#                 'error_messages': {
#                     'min_length': '仅允许8-20个字符的密码',
#                     'max_length': '仅允许8-20个字符的密码',
#                 }
#             }
#         }
#
# def validate_mobile(self, value):
#     # 手机号格式
#     if not re.match(r'^1[3-9]\d{9}$', value):
#         raise serializers.ValidationError('手机号格式不正确')
#
#     # 手机是否注册
#     count = User.objects.filter(mobile=value).count()
#
#     if count > 0:
#         raise serializers.ValidationError('手机号已存在')
#
#     return value

# def validate_allow(self, value):
#     # 是否同意协议
#     if value != 'true':
#         raise serializers.ValidationError('请同意协议')
#
#     return value

# def validate(self, attrs):
#     """
#     attrs: 字典，客户端传递所有数据
#     """
#     # 两次密码是否一致
#     password = attrs['password']
#     password2 = attrs['password2']
#
#     if password != password2:
#         raise serializers.ValidationError('两次密码不一致')
#
#     # 短信验证码是否正确
#     mobile = attrs['mobile']
#
#     # 获取redis链接
#     redis_conn = get_redis_connection('verify_codes')
#     real_sms_code = redis_conn.get('sms_%s' % mobile) # None bytes
#
#     if real_sms_code is None:
#         raise serializers.ValidationError('短信验证码已过期')
#
#     # 对比短信验证码
#     sms_code = attrs['sms_code'] # str
#
#     if real_sms_code.decode() != sms_code:
#         raise serializers.ValidationError('短信验证码错误')
#
#     return attrs

# def create(self, validated_data):
#     """
#     validated_data: 字典，校验之后的数据
#     """
#     # 移除无用的数据
#     del validated_data['password2']
#     del validated_data['sms_code']
#     del validated_data['allow']
#
#     # 创建新用户并保存到数据库
#     user = User.objects.create_user(**validated_data)
#
#     # 服务器生成一个jwt token的字符串：保留用户的身份信息
#     from rest_framework_jwt.settings import api_settings
#
#     # 生成payload的方法  载荷
#     jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
#     jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
#     payload = jwt_payload_handler(user)
#     token = jwt_encode_handler(payload)
#     # 给user增加token属性，保存jwt token的信息
#     user.token = token
#
#     return user

# 个人中心用户基本信息序列化器
class UserDetailSerializer(serializers.ModelSerializer):
    """
    个人中心用户基本信息序列化器
    """

    class Meta:
        model = User
        fields = ('id', 'username', 'mobile', 'email', 'email_active')


# 邮箱验证
class EmailSerializer(serializers.ModelSerializer):
    """邮箱序列化器类"""  # required 反序列化必须的

    class Meta:
        model = User
        fields = ('id', 'email')
        extra_kwargs = {
            'email': {
                'required': True
            }
        }

    # 重写update
    def update(self, instance, validated_data):
        """
         instance: user对象
         validated_data: 校验后的数据
        """
        # 设置登录用户的邮箱
        email = validated_data['email']
        instance.email = email
        instance.save()

        # TODO: 给邮箱发送验证邮件
        # 生成验证链接
        verify_url = instance.generate_verify_email_url()
        # 发送验证邮件
        from celery_tasks.email.tasks import send_verify_email
        send_verify_email.delay(email, verify_url)
        return instance


# 地址序列化器类
class AddressSerializer(serializers.ModelSerializer):
    # 关联对象嵌套序列化 字符串类型表示方法
    province = serializers.StringRelatedField(read_only=True)
    city = serializers.StringRelatedField(read_only=True)
    district = serializers.StringRelatedField(read_only=True)

    province_id = serializers.IntegerField(label='省ID', required=True)
    city_id = serializers.IntegerField(label='市ID', required=True)
    district_id = serializers.IntegerField(label='区ID', required=True)

    class Meta:
        model = Address
        exclude = ('user', 'is_deleted', 'create_time', 'update_time')

    # 手机号格式验证
    def validate_mobile(self, value):
        if not re.match(r'^1[3-9]\d{9}$', value):
            raise serializers.ValidationError('手机号格式验证错误')

        return value

    # 自带的create校验的方法中没有user，需重写
    def create(self, validated_data):
        """valited_data校验后的数据中不包括user对象"""
        # 获取登录用户   serializer = self.get_serializer()创建的时候产生了context
        # 在创建使用get_serializer时，kwargs['context'] = self.get_serializer_context()，会增加一个context字段
        # 取出user时，user = request.user
        user = self.context['request'].user

        # 保存新地址
        validated_data['user'] = user

        # 调用ModelSerializer中的create进行新增地址的创建
        return super().create(validated_data)


# 地址标题序列化类
class AddressTitleSerializer(serializers.ModelSerializer):
    """标题序列化器类"""

    class Meta:
        model = Address
        fields = ('title',)  # 元组要加上逗号


# 用户浏览记录序列化器类
class BrowseHistorySerializer(serializers.Serializer):
    """用户浏览记录序列化器"""
    sku_id = serializers.IntegerField(label='SKU商品ID')

    # sku_id 对应该商品是否存在
    def validate_sku_id(self, value):
        try:
            SKU.objects.get(id=value)
        except SKU.DoesNotExist:
            raise serializers.ValidationError('商品不存在')

        return value

    # 保存浏览记录
    def create(self, validated_data):
        """在redis中保存登录用户的浏览记录"""

        # 获取登录用户
        user = self.context['request'].user

        # 获取redis链接
        redis_conn = get_redis_connection('histories')

        # 保存信息
        # 拼接list key
        history_key = 'history_%s' % user.id
        # 1、去重
        sku_id = validated_data['sku_id']
        redis_conn.lrem(history_key, 0, sku_id)

        # 2、保存有序
        redis_conn.lpush(history_key, sku_id)

        # 3、截取返回
        redis_conn.ltrim(history_key, 0, constants.USER_BROWSING_HISTORY_COUNTS_LIMIT-1)

        # 返回
        return validated_data
